use proc_macro::TokenStream;

use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident, LitStr, parse_macro_input};

pub fn map_struct(arg: TokenStream, input: TokenStream) -> TokenStream {
    // Parse and validate the argument as a string literal

    let lit = match syn::parse::<LitStr>(arg.clone()) {
        Ok(lit) => lit,
        Err(_) => {
            return TokenStream::from(quote! {
                compile_error!("Attribute argument must be a string literal");
            });
        }
    };

    // Convert the string literal to an identifier
    let target_ident: Ident = syn::parse_str(&lit.value()).expect("Failed to parse target struct name");

    // Parse the input as a DeriveInput (expecting a struct)
    let input = parse_macro_input!(input as DeriveInput);
    // Ensure input is a struct
    if let Data::Struct(data_struct) = &input.data {
        let struct_ident = &input.ident;
        // Extract named fields of the input struct
        let fields = match &data_struct.fields {
            Fields::Named(fields) => &fields.named,
            _ => {
                return TokenStream::from(quote! {
                    compile_error!("Only named fields are supported");
                });
            }
        };

        // Get names of fields
        let field_names = fields.iter().map(|field| &field.ident);

        // Generate the `From` trait implementation with a different parameter name
        let expanded = quote! {
            impl From<#struct_ident> for #target_ident {
                fn from(source: #struct_ident) -> Self {
                    #target_ident {
                        #(#field_names: source.#field_names,)*
                    }
                }
            }
        };

        TokenStream::from(expanded)
    } else {
        TokenStream::from(quote! {
            compile_error!("Only structs are supported for conversion");
        })
    }
}
